package com.aierkeji.call.b2c.service;

import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import com.aierkeji.call.b2c.contants.Contants;
import com.aierkeji.call.b2c.dao.jpa.AkjCallUserDao;
import com.aierkeji.call.b2c.entity.AkjCallUser;
import com.aierkeji.call.b2c.entity.AkjCallVo;
import com.aierkeji.call.b2c.entity.vo.SearchOptionsVo;
import com.aierkeji.call.b2c.shiro.MyUserNamePasswordToken;
import com.aierkeji.call.b2c.util.AppConfig;
import com.aierkeji.call.b2c.util.DateTimeUtils;
import com.aierkeji.call.b2c.util.GsonUtils;
import com.aierkeji.call.b2c.util.ResultCode;
import com.aierkeji.call.b2c.util.ResultMapHelper;
import com.aierkeji.call.b2c.util.StringUtils;
import com.aierkeji.call.b2c.util.sms.SendSms;

@Service
public class AkjCallLoginService {
	private final Logger log = LogManager.getLogger(getClass());
	@Autowired
	private AkjCallUserDao akjCallUserDao;
	
	

	public Map<String, Object> getYZM(Map<String, Object> map) {
		
		String tel = (String) map.get("tel");
		//scene value  = registered
		String scene = (String) map.get("scene");
		if (StringUtils.checkAnyNull(tel, scene)) {
			return ResultMapHelper.nullParamsResult();
		}
		int count = akjCallUserDao.countByAccountAndIsDelete(tel, false);
		if (Contants.YZM_LOGIN.equals(scene)) {
			if (count <= 0) {
				return ResultMapHelper.failure("找不到该用户！");
			}
		} else {
			if (count > 0) {
				return ResultMapHelper.failure("当前手机号码已注册！");
			}
		}
		Date sendTime = (Date) SecurityUtils.getSubject().getSession().getAttribute(Contants.YZM_TIME + "_" + scene);
		Map<String, Object> sendResultMap = sendYZM(tel, sendTime, scene);
		if (ResultMapHelper.isSuccess(sendResultMap)) {
			Map<String, Object> data = (Map<String, Object>) sendResultMap.get("data");
			String yzm = (String) data.get("yzm");
			Date yzmTime = (Date) data.get(Contants.YZM_TIME);
			SecurityUtils.getSubject().getSession().setAttribute(Contants.YZM_KEY + "_" + scene, yzm);
			SecurityUtils.getSubject().getSession().setAttribute(Contants.YZM_TIME + "_" + scene, yzmTime);
			SecurityUtils.getSubject().getSession().setAttribute(Contants.YZM_TEL + "_" + scene, tel);
			SecurityUtils.getSubject().getSession().setAttribute(Contants.YZM_CHECK_COUNT + "_" + scene, 0);

			if (!"dev".equals(AppConfig.getProperty("env"))) {
				return ResultMapHelper.success();
			}

		}

		return sendResultMap;
	}

	public Map<String, Object> sendYZM(String tel, Date sendTime, String scene) {
		if (sendTime != null
				&& DateTimeUtils.addMinute(sendTime, Contants.YZM_SEND_TIME_MINUE.intValue()).after(new Date())) {
			return ResultMapHelper.failure("一个手机号码" + Contants.YZM_SEND_TIME_MINUE + "分钟之内只能发送一次短信");
		}

		int yzm = RandomUtils.nextInt(9999 - 1000 + 1) + 1000;
		String content = AppConfig.getPropertyEncoding("sms.yzm", "UTF-8");
		String systemName = "【" + AppConfig.getPropertyEncoding("sms.system.name", "UTF-8") + "】";
		SendSms sendSms = new SendSms(systemName, yzm + "", Contants.YZM_EXPIRATION_TIME_MINUE + "");
		Map<String, Object> map = sendSms.getSmsMap();
		content = StringUtils.processTemplate(content, map);
		boolean flag = false;
		try {
			flag = sendSms.send(content, tel);

		} catch (Exception e) {
			// TODO Auto-generated catch block
			log.error("sendYZM", e);
		}
		if (flag) {
		} else {
			return ResultMapHelper.failure("发送短信失败");
		}
		Map<String, Object> data = new HashMap<String, Object>();
		data.put("yzm", yzm + "");
		data.put(Contants.YZM_TIME, DateTimeUtils.getCurrentTime());

		return ResultMapHelper.success(data);
	}

	/**
	 * status = 105 会话过期 status = 99 验证失败，具体失败内容看msg 检测验证码
	 * 
	 * @param sessionYzm
	 * @param expirationTime
	 * @param yzm
	 * @return
	 */
	public Map<String, Object> checkYZM(Yzm yzmConfig) {
		String sessionYzm=yzmConfig.sessionYzm;
		Date sendTime = yzmConfig.sendTime;
		String sessionTel = yzmConfig.sessionTel;
		String yzm =yzmConfig.yzm;
		String tel = yzmConfig.tel;
		// TODO Auto-generated method stub
		if (sendTime == null || StringUtils.isEmpty(sessionYzm) || StringUtils.isEmpty(sessionTel)) {
			return ResultMapHelper.failure(ResultCode.CODE_ERROR_105, "会话过期，请重新刷新！");
		}
		if (DateTimeUtils.addMinute(sendTime, Contants.YZM_EXPIRATION_TIME_MINUE.intValue()).before(new Date())) {
			return ResultMapHelper.failure("验证码过期！请重新获取");
		}
		if (!sessionTel.equals(tel)) {
			return ResultMapHelper.failure("获取验证码手机号码与当前手机号不一致！请重新获取");
		}

		if (!sessionYzm.equals(yzm)) {
			yzmConfig.checkCount++;
			if(yzmConfig.checkCount>5) {
				return ResultMapHelper.failure(ResultCode.CODE_ERROR_106,"验证码错误超过5次，请重新获取！");
			}
			return ResultMapHelper.failure("验证码错误，请重新输入！");

		}
		return ResultMapHelper.success();
	}

	/**
	 * 注册
	 * 
	 * @param map
	 * @return
	 */
	public Map<String, Object> registered(Map<String, Object> map) {
		// TODO Auto-generated method stub
	
		String tel = (String) map.get("tel");
		String yzm = (String) map.get("yzm");
		String pwd = (String) map.get("pwd");
		if (StringUtils.checkAnyNull(tel, yzm, pwd)) {
			return ResultMapHelper.nullParamsResult();
		}
		Date sendTime = (Date) SecurityUtils.getSubject().getSession()
				.getAttribute(Contants.YZM_TIME + "_" + Contants.YZM_REGISTERED);
		String sessionYzm = (String) SecurityUtils.getSubject().getSession()
				.getAttribute(Contants.YZM_KEY + "_" + Contants.YZM_REGISTERED);
		String sessionTel = (String) SecurityUtils.getSubject().getSession()
				.getAttribute(Contants.YZM_TEL + "_" + Contants.YZM_REGISTERED);
		Integer checkCount = (Integer) SecurityUtils.getSubject().getSession()
				.getAttribute(Contants.YZM_CHECK_COUNT + "_" + Contants.YZM_REGISTERED);
		Yzm yzmConfig = new Yzm(sessionYzm, sendTime, sessionTel, yzm, tel, checkCount);
		Map<String, Object> checkResult = checkYZM(yzmConfig);
		if (ResultMapHelper.isSuccess(checkResult)) {
//			SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_TIME + "_" + Contants.YZM_REGISTERED);
//			SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_KEY + "_" + Contants.YZM_REGISTERED);
//			SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_TEL + "_" + Contants.YZM_REGISTERED);
//			SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_CHECK_COUNT + "_" + Contants.YZM_LOGIN);
			removeYZM(Contants.YZM_REGISTERED);
			int count = akjCallUserDao.countByAccountAndIsDelete(tel, false);
			if (count > 0) {
				return ResultMapHelper.failure("当前手机号码已注册！");
			} else {
				AkjCallUser akjCallUser = new AkjCallUser();
				akjCallUser.setAccount(tel);
				akjCallUser.setPwd(DigestUtils.md5DigestAsHex(pwd.getBytes()));
				akjCallUser.setCreatedAt(DateTimeUtils.getCurrentTime());
				akjCallUser.setName(DateTimeUtils.getCurrentTime().getTime() + "");
				this.akjCallUserDao.save(akjCallUser);
				return ResultMapHelper.success(akjCallUser);
			}
		} else {
			if(yzmConfig.checkCount>5) {
//				SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_TIME + "_" + Contants.YZM_REGISTERED);
//				SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_KEY + "_" + Contants.YZM_REGISTERED);
//				SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_TEL + "_" + Contants.YZM_REGISTERED);
//				SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_CHECK_COUNT + "_" + Contants.YZM_REGISTERED);
				removeYZM( Contants.YZM_REGISTERED);
			}else {
				SecurityUtils.getSubject().getSession().setAttribute(Contants.YZM_CHECK_COUNT + "_" + Contants.YZM_REGISTERED, yzmConfig.checkCount);

			}
			return checkResult;
		}

	}

	/**
	 * 验证码登陆
	 * 
	 * @param map
	 * @return
	 */
	public Map<String, Object> loginByYzm(Map<String, Object> map,HttpServletRequest request) {
		// TODO Auto-generated method stub
		String tel = (String) map.get("tel");
		String yzm = (String) map.get("yzm");
		if (StringUtils.checkAnyNull(tel, yzm)) {
			return ResultMapHelper.nullParamsResult();
		}
		Date sendTime = (Date) SecurityUtils.getSubject().getSession()
				.getAttribute(Contants.YZM_TIME + "_" + Contants.YZM_LOGIN);
		String sessionYzm = (String) SecurityUtils.getSubject().getSession()
				.getAttribute(Contants.YZM_KEY + "_" + Contants.YZM_LOGIN);
		String sessionTel = (String) SecurityUtils.getSubject().getSession()
				.getAttribute(Contants.YZM_TEL + "_" + Contants.YZM_LOGIN);
		Integer checkCount = (Integer) SecurityUtils.getSubject().getSession()
				.getAttribute(Contants.YZM_CHECK_COUNT + "_" + Contants.YZM_LOGIN);
		Yzm yzmConfig = new Yzm(sessionYzm, sendTime, sessionTel, yzm, tel, checkCount);

		Map<String, Object> checkResult = checkYZM(yzmConfig);
		if (ResultMapHelper.isSuccess(checkResult)) {
//			SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_TIME + "_" + Contants.YZM_LOGIN);
//			SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_KEY + "_" + Contants.YZM_LOGIN);
//			SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_TEL + "_" + Contants.YZM_LOGIN);
//			SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_CHECK_COUNT + "_" + Contants.YZM_LOGIN);
			removeYZM(Contants.YZM_LOGIN);
			AkjCallUser callUser = akjCallUserDao.findByAccountAndIsDelete(tel, false);
			if (callUser == null) {
				return ResultMapHelper.failure("登陆失败，账号或者密码错误！");
			}
			checkResult.put("data", callUser);
			return checkLoginSuccessAfter(checkResult,request);

		} else {
			if(yzmConfig.checkCount>5) {
//				SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_TIME + "_" + Contants.YZM_LOGIN);
//				SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_KEY + "_" + Contants.YZM_LOGIN);
//				SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_TEL + "_" + Contants.YZM_LOGIN);
//				SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_CHECK_COUNT + "_" + Contants.YZM_LOGIN);
				removeYZM(Contants.YZM_LOGIN);
			}else {
				SecurityUtils.getSubject().getSession().setAttribute(Contants.YZM_CHECK_COUNT + "_" + Contants.YZM_LOGIN, yzmConfig.checkCount);

			}
			return checkResult;
		}
	}
	
	
	private void removeYZM(String sence) {
		SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_TIME + "_" + sence);
		SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_KEY + "_" +sence);
		SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_TEL + "_" + sence);
		SecurityUtils.getSubject().getSession().removeAttribute(Contants.YZM_CHECK_COUNT + "_" + sence);
	}

	/**
	 * 密码登陆
	 * 
	 * @param map
	 * @return
	 */
	public Map<String, Object> loginByPassword(Map<String, Object> map,HttpServletRequest request) {
		// TODO Auto-generated method stub
		String tel = (String) map.get("tel");
		String pwd = (String) map.get("pwd");
		if (StringUtils.checkAnyNull(tel, pwd)) {
			return ResultMapHelper.nullParamsResult();
		}
		Map<String, Object> checkResult = loginByPassword(pwd, tel);
		if (ResultMapHelper.isSuccess(checkResult)) {
			
			return checkLoginSuccessAfter(checkResult,request);
		} else {
			return checkResult;
		}
	}

	/**
	 * 登陆检验通过后
	 * 
	 * @param checkResult
	 * @return
	 */
	private Map<String, Object> checkLoginSuccessAfter(Map<String, Object> checkResult,HttpServletRequest request) {
		AkjCallUser callUser 		= (AkjCallUser) checkResult.get("data");
		UsernamePasswordToken token = new MyUserNamePasswordToken(callUser, callUser.getPwd());
		AkjCallVo vo 				= new AkjCallVo();
		Subject subject			 	= SecurityUtils.getSubject();
		try {
			
			subject.login(token);
			subject.getSession().setAttribute("loginUser", callUser);
			
			SecurityUtils.getSubject().getSession()
					.setTimeout(Long.parseLong(AppConfig.getProperty("sessionTimout", (3000L * 60 * 10) + "")));
			subject.isPermitted("666");
			if(!CollectionUtils.isEmpty(callUser.getRoles())) {
				callUser.setRolesCode(callUser.getRoles().stream().map(k->k.getCode()).collect(Collectors.toSet()));
			}
			
			BeanUtils.copyProperties(vo, callUser);
			
			callUser.setVersion(request.getHeader("versionName"));
			akjCallUserDao.save(callUser);
			
			
		} catch (UnknownAccountException uae) {
			return ResultMapHelper.result(ResultCode.CODE_ERROR_101, "账户不存在");
		} catch (IncorrectCredentialsException ice) {
			return ResultMapHelper.result(ResultCode.CODE_ERROR_102, "密码错误");
		} catch(Exception e) {
			e.printStackTrace();
			return ResultMapHelper.failure("系统出错拉！");
		} 
		
		return ResultMapHelper.success(vo);
	}

	/**
	 * 检验登陆信息
	 * 
	 * @param pwd
	 * @param tel
	 * @return
	 */
	public Map<String, Object> loginByPassword(String pwd, String tel) {
		if (StringUtils.checkAnyNull(tel, pwd)) {
			return ResultMapHelper.nullParamsResult();
		}
		AkjCallUser callUser = akjCallUserDao.findByAccountAndIsDelete(tel, false);
		if (callUser == null) {
			return ResultMapHelper.failure("登陆失败，账号或者密码错误！");
		}
		if (callUser.getPwd().equals(DigestUtils.md5DigestAsHex(pwd.getBytes()))) {
			return ResultMapHelper.success(callUser);
		}
		return ResultMapHelper.failure("登陆失败，账号或者密码错误！");
	}
	
	public Yzm buildYzmConfig(String sessionYzm, Date sendTime, String sessionTel, String yzm, String tel, Integer checkCount) {
		return new Yzm(sessionYzm, sendTime, sessionTel, yzm, tel, checkCount);
	}

	class Yzm {
		private String sessionYzm;
		private Date sendTime;
		private String sessionTel;
		private String yzm;
		private String tel;
		private int checkCount = 0;
		public Yzm(String sessionYzm, Date sendTime, String sessionTel, String yzm, String tel, Integer checkCount) {
			super();
			this.sessionYzm = sessionYzm;
			this.sendTime = sendTime;
			this.sessionTel = sessionTel;
			this.yzm = yzm;
			this.tel = tel;
			this.checkCount = checkCount==null?0:checkCount;
		}
	}

	public Map<String, Object> getUserInfo(Map<String, Object> map) {
		Map<String, Object> resultMap = new HashMap<String, Object>();
		
		AkjCallUser user = (AkjCallUser) SecurityUtils.getSubject().getSession().getAttribute("loginUser");
		
		AkjCallVo vo = new AkjCallVo();
		try {
			BeanUtils.copyProperties(vo, user);
			vo.setBirth(vo.getBirth());
			resultMap.put("data", vo);
		} catch (Exception e) {
			log.error(e.getMessage());
			return ResultMapHelper.failure("查询出错拉！");
		} 
		return resultMap;
	}

	public Map<String, Object> updateUserInfo(Map<String, Object> map) {
		AkjCallVo vo = GsonUtils.transMapToObj(map,AkjCallVo.class);
		
		AkjCallUser user = (AkjCallUser) SecurityUtils.getSubject().getSession().getAttribute("loginUser");
		if(vo.getBirth()!=null) user.setBirth(vo.getBirth());
		if(vo.getGender()!=null)user.setGender(vo.getGender());
		if(vo.getName()!=null)user.setName(vo.getName());
		
		try {
			if(!"".equals(vo.getNewPwd())&&vo.getNewPwd()!=null) {
				if(user.getPwd().equals(DigestUtils.md5DigestAsHex(vo.getNewPwd().getBytes()))) {
					return ResultMapHelper.failure("与当前密码一致，请选用其他密码");
				}
				
				user.setPwd(DigestUtils.md5DigestAsHex(vo.getNewPwd().getBytes()));
			}
			akjCallUserDao.save(user);
			
			BeanUtils.copyProperties(vo, user);
			
			SecurityUtils.getSubject().getSession().setAttribute("loginUser", user);
			
		}catch (Exception e) {
			log.error(e.getMessage());
			return ResultMapHelper.failure("修改用户出错拉！");
		}
		return ResultMapHelper.success(vo);
	}

	public Map<String, Object> getAssigneUser(Map<String, Object> map) {
		// TODO Auto-generated method stub
		AkjCallUser user = (AkjCallUser) SecurityUtils.getSubject().getSession().getAttribute("loginUser");
		List<SearchOptionsVo> list = this.akjCallUserDao.findCanAssigneUser(user.getId());
		return ResultMapHelper.success(list);
	}

	public Map<String, Object> uploadAppLogs(MultipartFile file) {
		// TODO Auto-generated method stub
		
		String path = AppConfig.getProperty("appLogPath");
		AkjCallUser user = (AkjCallUser) SecurityUtils.getSubject().getSession().getAttribute("loginUser");
		
		String dateStr = DateTimeUtils.converDateToString(DateTimeUtils.getCurrentTime(),DateTimeUtils.DATE_PATTERN_DAY);
		try{
			file.transferTo(new File(path+dateStr+" "+user.getName()));
			
			return ResultMapHelper.success();
		}catch(Exception e){
			log.error(e.getMessage());
			return ResultMapHelper.failure("上传日志文件出错了");
		}
		
	}
}
